package com.koron.util;

import com.koron.common.mapper.PrintMapper;
import com.koron.css2.ApplicationConfig;
import com.koron.css2.serviceManage.bean.UserInfoBean;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.css2.serviceManage.utils.RedisUtils;
import com.koron.print.FieldBean;
import com.koron.print.PrintCenter;
import com.koron.print.PrintInterface;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.koron.ebs.mybatis.ADOConnection;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

//import redis.clients.jedis.Jedis;
//import redis.clients.jedis.JedisPool;

public class PrintInterfaceImpl implements PrintInterface {
    private static Logger logger = LogManager.getLogger(PrintInterfaceImpl.class);

//	public static JedisPool jedisPool; // redis缓存池

    public PrintInterfaceImpl() {
//		PrintInterfaceImpl.jedisPool = jedisPool;
        //初始化打印中心
        PrintCenter.setPrintInterface(this);
    }

    /**
     * 取对应报表的字段信息，根据参数formatFileName找到对应报表的字段信息并返回
     * 可能的实现方式是建立数据表存储打印格式文件名和字段信息，这里通过formatFileName找出对应的字段信息并返回
     */
    @Override
    public ArrayList<FieldBean> getFieldList(java.lang.String templateId) {
        //formatFileName格式为水司编号_格式文件名
        if (templateId == null || templateId.indexOf("$$$") == -1)
            throw new RuntimeException("格式文件名称不正确");
        //取水司信息
        String companyNo = null;
        if (templateId.indexOf("_") > -1) {
            companyNo = templateId.substring(0, templateId.indexOf("_"));
            templateId = templateId.substring(templateId.indexOf("_") + 1);
        }
        //取登陆token
        String token = templateId.substring(0, templateId.indexOf("$$$"));
        templateId = templateId.substring(templateId.indexOf("$$$") + 3);
        // 获取用户信息(包括用户信息，用户可选水司信息，用户当前水司信息)
        UserInfoBean userInfo = Tools.getLoginBean(token);
        if (userInfo == null || StringUtils.isBlank(token)) {
            throw new RuntimeException("用户未登陆");
        }
        if (companyNo == null) {
            companyNo = userInfo.getCurWaterCode();
        }
        String env = "_default";
        if (!companyNo.equals(ApplicationConfig.getWaterCodeFilter())) {
            env = DBSourceUtils.getDbEnv(companyNo);
        }

        String bussnessId;
        //如果格式文件名以businessCode_开头，表示采用此业务单据的默认模板
        if (templateId.startsWith("businessCode_")) {
            String businessCode = templateId.substring("businessCode_".length());
            bussnessId = ADOConnection.runTask("_default", (factory) -> {
                PrintMapper mapper = factory.getMapper(PrintMapper.class);
                return mapper.getBusinuessIdByCode(businessCode);
            }, String.class);
        } else {
            String tId = templateId;
            //根据模板id,查询业务id
            bussnessId = ADOConnection.runTask(env, (factory) -> {
                PrintMapper mapper = factory.getMapper(PrintMapper.class);
                return mapper.getBusinessId(tId);
            }, String.class);
        }
        String fieldStr = ADOConnection.runTask("_default", (factory) -> {
            PrintMapper mapper = factory.getMapper(PrintMapper.class);
            return mapper.getFieldList(bussnessId);
        }, String.class);
        ArrayList<FieldBean> fbList = new ArrayList<>();
        try {
            ArrayList<?> jlist = JsonUtils.jsonToPojo(fieldStr, ArrayList.class);
            for (Object o : jlist) {
                Map<?, ?> m = (Map<?, ?>) o;
                FieldBean fb = new FieldBean(m.get("fieldCode") + "", m.get("fieldName") + "", (Integer) m.get("fieldType"));
                fbList.add(fb);
            }
        } catch (Exception e) {
            throw new RuntimeException("格式转换错误", e);
        }

        return fbList;
    }

    /**
     * 根据文件名formatFileName取打印格式文件的byte字节流
     * 对于在本地服务器以文件的方式存储打印格式文件的，请实现方法getFilePath(java.lang.String) 这里返回null即可
     * 对于不在本地以文件方式存储的，比如存储在数据库或者文件服务器上的，通过本方法根据formatFileName读取格式文件的byte数组，注意文件以utf_8编码
     */
    @Override
    public byte[] getFileBytes(java.lang.String templateId) {
        //formatFileName格式为水司编号_格式文件名
        if (templateId == null || templateId.indexOf("$$$") == -1)
            throw new RuntimeException("格式文件名称不正确");
        //取水司信息
        String companyNo = null;
        if (templateId.indexOf("_") > -1) {
            companyNo = templateId.substring(0, templateId.indexOf("_"));
            templateId = templateId.substring(templateId.indexOf("_") + 1);
        }
        //取登陆token
        String token = templateId.substring(0, templateId.indexOf("$$$"));
        templateId = templateId.substring(templateId.indexOf("$$$") + 3);
        // 获取用户信息(包括用户信息，用户可选水司信息，用户当前水司信息)
        UserInfoBean userInfo = Tools.getLoginBean(token);
        if (userInfo == null || StringUtils.isBlank(token)) {
            throw new RuntimeException("用户未登陆");
        }
        if (companyNo == null) {
            companyNo = userInfo.getCurWaterCode();
        }
        String env = "_default";
        if (!companyNo.equals(ApplicationConfig.getWaterCodeFilter())) {
            env = DBSourceUtils.getDbEnv(companyNo);
        }

        //如果格式文件名以businessCode_开头，表示采用此业务单据的默认模板
        if (templateId.startsWith("businessCode_")) {
            String businessCode = templateId.substring("businessCode_".length());
            //根据业务id查默认模板，模板可能存在无权限范围的情况
            templateId = getDefaultTemplate(businessCode, userInfo, env);
        }
        String tId = templateId;

        //根据模板id,查询业务id
        final String template = ADOConnection.runTask(env, (factory) -> {
            PrintMapper mapper = factory.getMapper(PrintMapper.class);
            return mapper.getTemplate(tId);
        }, String.class);
        if (StringUtils.isBlank(template)) {
            return new byte[]{};
        }
        try {
            return template.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("不支持的编码格式");
        }
    }

    /**
     * 读取默认模板
     *
     * @param businessCode
     * @param userInfo
     * @param env
     * @return
     */
    private java.lang.String getDefaultTemplate(java.lang.String businessCode, UserInfoBean userInfo, String env) {
        //根据businessCode 查询业务id
        String bussnessId = ADOConnection.runTask("_default", (factory) -> {
            PrintMapper mapper = factory.getMapper(PrintMapper.class);
            return mapper.getBusinuessIdByCode(businessCode);
        }, String.class);
        if (StringUtils.isBlank(bussnessId)) {
            throw new RuntimeException("打印业务编号" + businessCode + "不存在");
        }
        //根据业务id查询所有样式模板
        @SuppressWarnings("unchecked")
        ArrayList<HashMap<String, String>> list = ADOConnection.runTask(env, (factory) -> {
            PrintMapper mapper = factory.getMapper(PrintMapper.class);
            return mapper.getTemplateDefault(bussnessId);
        }, ArrayList.class);
        for (HashMap<String, String> m : list) {
            String id = m.get("ID");
            String scope = m.get("SCOPE");
            if (StringUtils.isBlank(scope)) {
                return id;
            } else {
                String us[] = scope.split("[,，;；]{1}");
                boolean found = false;
                for (String u : us) {
                    if (userInfo.getUserInfo().getAcount().equals(u)) {
                        found = true;
                        break;
                    }
                }
                if (found) {
                    return id;
                }
            }
        }
        throw new RuntimeException("打印业务编号" + businessCode + "在当前用户" + userInfo.getUserInfo().getAcount() + "无可用模板");
    }

    /**
     * 取打印格式文件存储路径,可以根据文件名formatFileName返回不同的路径
     * 对于在本地服务器以文件的方式存储打印格式文件的，这里只需指定格式文件存储的路径即可
     * 对于不在本地以文件方式存储的，比如存储在数据库或者文件服务器上的，本方法必须返回null,通过实现 getFileBytes(java.lang.String) 方法直接读取文件的byte数组
     */
    @Override
    public String getFilePath(java.lang.String formatFileName) {
        return null;
    }

    /**
     * 取需打印的数据列表。
     */
    @SuppressWarnings("unchecked")
    @Override
    public ArrayList<HashMap<String, String>> getPrintData(java.lang.String key) {
        key = "printdata" + key;
//		Jedis resource = null;
        try {
//			resource = jedisPool.getResource();
//			String pong = resource.ping();
//			if (resource == null || pong == "PONG") {
//				return null;
//			}else {

            String data = RedisUtils.get(key);
            RedisUtils.del(key);
            return JsonUtils.jsonToPojo(data, ArrayList.class);
//			}
        } catch (Exception e) {
            logger.error("服务器异常", e);
            return null;
        }
    }

    /**
     * 设置打印数据
     *
     * @param key
     * @param data
     * @throws Exception
     */
    public static String setPrintData(ArrayList<HashMap<String, String>> data) throws Exception {
        String key = UUID.randomUUID().toString();
        PrintInterfaceImpl.setPrintData(key, data);
        return key;
    }

    /**
     * 设置打印数据
     *
     * @param key
     * @param data
     * @throws Exception
     */
    public static void setPrintData(String key, ArrayList<HashMap<String, String>> data) throws Exception {
        key = "printdata" + key;
//		Jedis resource = null;
        try {
//			resource = jedisPool.getResource();
//			String pong = resource.ping();
//			if (resource == null || pong == "PONG") {
//				throw new Exception("缓存服务器异常");
//			}else {
            RedisUtils.set(key, JsonUtils.objectToJson(data));
            RedisUtils.expire(key, 5 * 60000);//打印数据5分钟过期
//			}
        } catch (Exception e) {
            logger.error("服务器异常", e);
            throw new Exception("缓存异常");
        } finally {
//			if (resource != null) {
//				resource.close();
//			}
        }
    }

    /**
     * 提供打印格式文件字节数组，可用此方法来实现格式文件存储到数据库或文件服务器
     * 对于在本地服务器以文件的方式存储打印格式文件的，请实现方法getFilePath(java.lang.String)， 本方法不会被执行，故无需实现，
     * 未实现getFilePath方法的，必须采用本方法实现文件的存储，比如可以把文件存储到数据库，或文件服务器，注意格式文件是一个文本文件，如果存数据库建议转字附串存储。
     */
    @Override
    public void writeFileBytes(java.lang.String templateId, byte[] bytes) {
        //formatFileName格式为水司编号_格式文件名
        if (templateId == null || templateId.indexOf("$$$") == -1)
            throw new RuntimeException("格式文件名称不正确");
        //取水司信息
        String companyNo = null;
        if (templateId.indexOf("_") > -1) {
            companyNo = templateId.substring(0, templateId.indexOf("_"));
            templateId = templateId.substring(templateId.indexOf("_") + 1);
        }
        //取登陆token
        String token = templateId.substring(0, templateId.indexOf("$$$"));
        templateId = templateId.substring(templateId.indexOf("$$$") + 3);
        // 获取用户信息(包括用户信息，用户可选水司信息，用户当前水司信息)
        UserInfoBean userInfo = Tools.getLoginBean(token);
        if (userInfo == null || StringUtils.isBlank(token)) {
            throw new RuntimeException("用户未登陆");
        }
        if (companyNo == null) {
            companyNo = userInfo.getCurWaterCode();
        }
        String env = "_default";
        if (!companyNo.equals(ApplicationConfig.getWaterCodeFilter())) {
            env = DBSourceUtils.getDbEnv(companyNo);
        }
        // 获取用户信息(包括用户信息，用户可选水司信息，用户当前水司信息)
        // 写格式文件不对token进行校验，因为设计可能经过较时间，存在会话失效的问题，只要能登记可认为是经过授权的

        //如果格式文件名以businessCode_开头，表示采用此业务单据的默认模板
        if (templateId.startsWith("businessCode_")) {
            throw new RuntimeException("格式设计必须指定模板id,不可以传入打印业务编号");
        }
        String tId = templateId;

        //根据模板id,查询业务id
        ADOConnection.runTask(env, (factory) -> {
            PrintMapper mapper = factory.getMapper(PrintMapper.class);
            try {
                return mapper.updateTemplate(tId, new String(bytes, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("不支持的编码格式");
            }
        }, Integer.class);
    }

}
